#!/bin/bash
#
# Copyright 2015-2017 Adrian DC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# === Repo Init AOSP ===
function repoinitaosp()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: repoinitaosp <branch_id> [referenced,clean,light/shallow,example] (repo init for AOSP)';
    echo '';
    echo ' Branch identifications:';
    echo '  - android-<X.X.X_rXX>';
    echo '  - android-<X-preview-X>';
    echo '  - master';
    echo '';
    return;
  fi;

  # Variables
  local release=${1};
  local params=${2};
  local branch;
  local init_command;
  local depth=;

  # Branch selection
  if [ "${release}" = 'master' ]; then
    branch="${release}";
  else
    branch="android-${release}";
  fi;

  # Repo shallow
  if [[ "${params}" == *'shallow'* ]]; then
    depth='--depth 1';
  elif [[ "${params}" == *'light'* ]]; then
    depth="--depth ${ANDROID_REPO_INIT_LIGHT:-100}";
  fi;

  # Repo init command
  if [[ "${params}" == *'referenced'* ]]; then
    init_command="repo init -u http://android.googlesource.com/platform/manifest -b ${branch} ${depth} --reference=$(readlink -f "$(getand)/AOSP")";
  else
    init_command="repo init -u http://android.googlesource.com/platform/manifest -b ${branch} ${depth}";
  fi;

  # Output init command
  echo '';
  echo " ${init_command}";
  echo '';

  # Exit init for examples only
  if [[ "${params}" == *'example'* ]]; then
    return;
  fi;

  # Prepare synced objects for migrations
  if [[ ! "${params}" == *'clean'* ]] && [[ ! "${params}" == *'light'* ]] && [[ ! "${params}" == *'shallow'* ]]; then
    ${init_command};
    reposy;
  fi;

  # Clean repo manifest
  repoinitcleaner "${params}";

  # Launch init command
  ${init_command};

  # Exit on repo init failure
  if [ ! -d .repo/manifests ]; then
    echo "repoinitaosp failed for ${branch}";
    return;
  fi;

  # Unneeded branches cleanup
  cd .repo/manifests/;
  git tag | grep -v "${branch}" | xargs git tag -d > /dev/null;
  echo "repoinitaosp done for ${branch}";
  echo '';
  cd ../../;

  # Post-clean repo manifest
  repoinitsafecleaner "${params}";
}

# === Repo Init LineageOS ===
function repoinitlineage()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: repoinitlineage <13.0/14.1/15.0> [referenced,clean,light/shallow,example] (repo init for LineageOS)';
    echo '';
    return;
  fi;

  # Variables
  local release=${1};
  local params=${2};
  local branch;
  local init_command;
  local depth=;

  # Handle branches
  case ${release} in
    13.0) branch='cm-13.0';;
    14.1) branch='cm-14.1';;
    15.0) branch='lineage-15.0';;
    *)    branch='';;
  esac;

  # Repo shallow
  if [[ "${params}" == *'shallow'* ]]; then
    depth='--depth 1';
  elif [[ "${params}" == *'light'* ]]; then
    depth="--depth ${ANDROID_REPO_INIT_LIGHT:-100}";
  fi;

  # Repo init command
  if [[ "${params}" == *'referenced'* ]]; then
    init_command="repo init -u http://github.com/LineageOS/android.git -b ${branch} ${depth} --reference=$(readlink -f "$(getand)/LineageOS")";
  else
    init_command="repo init -u http://github.com/LineageOS/android.git -b ${branch} ${depth}";
  fi;

  # Output init command
  echo '';
  echo " ${init_command}";
  echo '';

  # Exit init for examples only
  if [[ "${params}" == *'example'* ]]; then
    return;
  fi;

  # Prepare synced objects for migrations
  if [[ ! "${params}" == *'clean'* ]] && [[ ! "${params}" == *'light'* ]] && [[ ! "${params}" == *'shallow'* ]]; then
    ${init_command};
    reposy;
  fi;

  # Clean repo manifest
  repoinitcleaner "${params}";

  # Launch init command
  ${init_command};

  # Exit on repo init failure
  if [ ! -d .repo/manifests ]; then
    echo "repoinitlineage failed for ${branch}";
    return;
  fi;

  # Unneeded branches cleanup
  cd .repo/manifests/;
  git tag | grep -v "${branch}" | xargs git tag -d > /dev/null;
  echo "repoinitlineage done for ${branch}";
  echo '';
  cd ../../;

  # Post-clean repo manifest
  repoinitsafecleaner "${params}";
}

# === Repo Init ResurrectionRemix ===
function repoinitrr()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: repoinitrr <nougat> [referenced,clean,light/shallow] (repo init for ResurrectionRemix)';
    echo '';
    return;
  fi;

  # Variables
  local release=${1};
  local params=${2};
  local branch=${release};
  local depth=;

  # Repo shallow
  if [[ "${params}" == *'shallow'* ]]; then
    depth='--depth 1';
  elif [[ "${params}" == *'light'* ]]; then
    depth="--depth ${ANDROID_REPO_INIT_LIGHT:-100}";
  fi;

  # Prepare synced objects for migrations
  if [[ ! "${params}" == *'clean'* ]] && [[ ! "${params}" == *'light'* ]] && [[ ! "${params}" == *'shallow'* ]]; then
    reposy;
  fi;

  # Clean repo manifest
  repoinitcleaner "${params}";

  # Repo init
  if [[ "${params}" == *'referenced'* ]]; then
    repo init -u http://github.com/ResurrectionRemix/platform_manifest.git \
              -b "${branch}" \
              "${depth}" \
              --reference="$(readlink -f "$(getand)/LineageOS")";
  else
    repo init -u http://github.com/ResurrectionRemix/platform_manifest.git \
              -b "${branch}" \
              "${depth}";
  fi;

  # Exit on repo init failure
  if [ ! -d .repo/manifests ]; then
    echo "repoinitrr failed for ${branch}";
    return;
  fi;

  # Unneeded branches cleanup
  cd .repo/manifests/;
  git tag | grep -v "${branch}" | xargs git tag -d;
  echo "repoinitrr done for ${branch}";
  cd ../../;

  # Post-clean repo manifest
  repoinitsafecleaner "${params}";
}

# === Repo Init TWRP ===
function repoinittwrp()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: repoinittwrp <twrp-{X.X}> [referenced,clean,light/shallow] (repo init for TWRP)';
    echo '';
    return;
  fi;

  # Variables
  local release=${1};
  local params=${2};
  local branch=twrp-${release};
  local depth=;

  # Repo shallow
  if [[ "${params}" == *'shallow'* ]]; then
    depth='--depth 1';
  elif [[ "${params}" == *'light'* ]]; then
    depth="--depth ${ANDROID_REPO_INIT_LIGHT:-100}";
  fi;

  # Wipe the out folder
  repoclean;

  # Clean repo manifest
  repoinitcleaner "${params}";

  # Repo init
  if [[ "${params}" == *'referenced'* ]]; then
    repo init -u https://github.com/minimal-manifest-twrp/platform_manifest_twrp_omni.git \
              -b "${branch}" \
              "${depth}" \
              --reference="$(readlink -f "$(getand)/TWRP")";
  else
    repo init -u https://github.com/minimal-manifest-twrp/platform_manifest_twrp_omni.git \
              -b "${branch}" \
              "${depth}";
  fi;

  # Exit on repo init failure
  if [ ! -d .repo/manifests ]; then
    echo "repoinittwrp failed for ${branch}";
    return;
  fi;

  # Unneeded branches cleanup
  cd .repo/manifests/;
  git tag | grep -v "${branch}" | xargs git tag -d;
  echo "repoinittwrp done for ${branch}";
  cd ../../;

  # Post-clean repo manifest
  repoinitsafecleaner "${params}";
}

# === Repo Init Cleaner ===
function repoinitcleaner()
{
  # Usage: repoinitcleaner [clean] (repo init cleaner)

  # Run the safety cleaner before removing repo
  repoinitsafecleaner "${1}";

  # Cleanup repo and manifests
  rm -rfv .repo/manifests;
  rm -rfv .repo/manifests.git;
  rm -rfv .repo/manifest.xml;
  rm -rfv .repo/repo;

  # Cleanup project files and history if requested
  if [[ "${1}" == *'clean'* ]]; then
    rm -rfv .repo/project.list;
    rm -rfv .repo/projects;
    rm -rfv .repo/project-objects;
    rm -rfv ./*;
  fi;

  # Cleanup known faulty projects
  rm -rfv prebuilts/qemu-kernel;
  rm -rfv .repo/projects/prebuilts/qemu-kernel.git;
  rm -rfv .repo/project-objects/prebuilts/qemu-kernel.git;
}

# === Repo Init Safe Cleaner ===
function repoinitsafecleaner()
{
  # Usage: repoinitsafecleaner [clean] (repo init safety cleaner)

  # Variables
  local temp_list_grep;

  # Prepare temp files
  temp_list_grep=$(mktemp);

  # Function header
  echo '';
  echo " repoinitsafecleaner: Searching for nested projects...";

  # Detect missing project.list
  if [ ! -f .repo/project.list ]; then
    reposy bionic;
  fi;

  # Detect nested projects causing sync issues
  cp .repo/project.list "${temp_list_grep}";
  while IFS= read -r path; do
    if [ ! "${path: -1}" = '/' ]; then
      path="${path}/";
    fi;
    if grep -q "${path}" "${temp_list_grep}"; then
      echo " repoinitsafecleaner: '${path}' has nested projects, deleting...";
      rm -rfv "${path}";
    fi;
  done < '.repo/project.list';

  # Detect symlinked repo files causing leftovers
  grep 'copyfile\|linkfile' .repo/manifests/*.xml .repo/manifests/*/*.xml \
      | sed 's/.*dest="\([^\"]*\)".*/\1/g' \
      | xargs -n1 echo rm -fv;

  # Remove temporary files
  rm -f "${temp_list_grep}";
  echo '';
}

# === Repo Init Menu ===
function repoinit()
{
  # Usage: repoinit [bool_manually] (repo init menu)

  # Variables
  local branch;
  local cnt=0;
  local key;
  local line_function;
  local line_usage;
  local list_functions=('');
  local options;
  local options_list;
  local options_prepend='';
  local options_referenced;
  local search_branch;
  local search_repo;

  # Reset inputs
  key='';
  search_branch='';
  search_repo='';

  # Detect the existence of roomservice.xml
  if [ -z "${1}" ] && [ -f '.repo/local_manifests/roomservice.xml' ]; then
    search_repo=$(grep "Repo Init: '" '.repo/local_manifests/roomservice.xml' | sed "s/.* '\(.*\)' .*/\1/");
    if [ ! -z "${search_repo}" ]; then

      # Extract repoinit tags
      search_branch=${search_repo#* };
      search_repo=${search_repo% *};
      echo '';
      echo -e  " \e[1;32mDetected repoinit to use : '${search_repo}' with branch '${search_branch}'\e[0m ";

    fi;
  fi;

  # Display exit item
  echo '';
  echo -e "  \e[1;33m0: \e[1;37mKeep current repo \e[1;32m[Exit the configuration]\e[0m";

  # Display shtools* menu
  for line_function in $(typeset -F | grep ' repoinit' | cut -d' ' -f 3 | grep -v '^repoinit$' | grep -v 'all$'); do

    # Parse usage
    line_usage=$(grep -a "Usage: ${line_function} " "${ANDROID_DEVELOPMENT_SHELL_TOOLS_SOURCES[@]}");
    if [ -z "${line_usage}" ]; then
      continue;
    fi;
    line_usage=${line_usage#*\(};
    line_usage=${line_usage%\)*};
    list_functions+=("${line_function}");

    # Item choice
    cnt=$((cnt + 1));
    if [ "${line_function}" = "${search_repo}" ]; then
      key=${cnt};
    fi;
    echo -e "  \e[1;33m${cnt}: \e[1;37m${line_function} \e[1;32m[${line_usage}]\e[0m";

  done;
  echo '';

  # Request user input
  echo -en " \e[1;37m> Command to run [0-${cnt}] :\e[0m ";
  if [ -z "${key}" ]; then
    read -r key;
    search_branch='';
  else
    echo "${key}";
  fi;

  # Abort on exit
  if [ -z "${key}" ] || [ "${key}" -eq 0 ]; then
    echo '';
    return;
  fi;

  # Show repo init usage
  echo -en "\e[1;33m";
  ${list_functions[${key}]};
  echo -en "\e[0m";

  # Get options list
  options_list=$(${list_functions[${key}]} \
               | grep 'Usage:');
  options_list=${options_list#*[};
  options_list=${options_list%]*};

  # Request branch input
  echo -en " \e[1;37m> Branch to track :\e[0m ";
  if [ -z "${search_branch}" ]; then
    read -r branch;
  else
    branch=${search_branch};
    echo "${branch}";
  fi;
  echo '';

  # Request or retrieve referenced repo option
  if [[ "${options_list}" == *'referenced'* ]] && [ ! "${ANDROID_REPO_INIT_REFERENCED}" = 'n' ]; then
    echo -en " \e[1;37m> Referenced repository [y/N] :\e[0m ";
    if [ -s '.repo/local_manifests/.repoinit.referenced' ]; then
      options_referenced=$(cat '.repo/local_manifests/.repoinit.referenced');
      echo "${options_referenced}";
    else
      read -r options_referenced;
    fi;
    if [ ! -z "${options_referenced}" ] && [[ 'yY' == *"${options_referenced}"* ]]; then
      options_prepend='referenced';
      options_list=${options_list/referenced/};
      echo -n 'y' > '.repo/local_manifests/.repoinit.referenced';
    else
      options_prepend='';
      echo -n 'n' > '.repo/local_manifests/.repoinit.referenced';
    fi;
  fi;

  # Cleanup options list
  options_list=${options_list#,};
  options_list=${options_list%,};

  # Request or retrieve repo options
  echo -en " \e[1;37m> Options to use [${options_list}] :\e[0m ";
  if [ -z "${search_branch}" ] || [ -z "${ANDROID_REPO_INIT_OPTIONS}" ]; then
    if [ -f '.repo/local_manifests/.repoinit.options' ]; then
      options=$(cat '.repo/local_manifests/.repoinit.options');
      echo "${options}";
    else
      read -r options;
    fi;
    echo -n "${options}" > '.repo/local_manifests/.repoinit.options';
    options="${options_prepend},${options}";
  else
    options="${options_prepend},${ANDROID_REPO_INIT_OPTIONS}";
    echo "${options}";
  fi;

  # Show repo init command
  echo '';
  echo -e " \e[1;33m> Launching:\e[0m ${list_functions[${key}]} ${branch} ${options}";
  echo '';

  # Launch repo init command
  ${list_functions[${key}]} "${branch}" "${options}";
}
